using System;
using System.Collections.Generic;
using System.Text;
using GarageGames.Torque.Core;
using Microsoft.Xna.Framework;
using Xyne.Utilities;
using GarageGames.Torque.Sim;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Graphics;
using Xyne.Objects.Common;
using GarageGames.Torque.Materials;
using Xyne.Templates;
using GarageGames.Torque.Platform;
using Xyne.Templates.Card;
using GarageGames.Torque.T2D;

namespace Xyne.GUI.GUIControls.Menu
{
    public class CircleMenu : MenuItem
    {
        #region Members

        public delegate void MenuShownDelegate();
        public delegate void MenuCanceledDelegate();
        private MenuShownDelegate _menuShown;
        private MenuCanceledDelegate _menuCancelled;

        private List<MenuItem>  _menuItems;
        private Queue<MenuItem> _menuItemsToRender;
        private float _radius;
        private string _menuName;
        private bool _showing;        

        private MenuManager _manager;

        private InputMap _oldInputMap;

        private float _selectedX;
        private float _selectedY;

        private MenuItem _currentlySelected;

        private Vector2 DefaultPosition = new Vector2(200, 200);

        private Vector2 _defaultSize = new Vector2(150, 50);

        private int _menuDepth;

        private T2DStaticSprite background;
        #endregion

        #region Properties
        public int MenuDepth
        {
            get
            {
                return _menuDepth;
            }

            set
            {
                _menuDepth = value;
            }
        }

        public string MenuName
        {
            get
            {
                return _menuName;
            }

            set
            {
                _menuName = value;
                _menuItemsToRender.Enqueue(this);
            }
        }

        public MenuManager Manager
        {
            get
            {
                return _manager;
            }

            set
            {
                _manager = value;

                _manager.AddMenu(this);
            }
        }

        public MenuShownDelegate MenuShown
        {
            get
            {
                return _menuShown;
            }

            set
            {
                _menuShown = value;
            }
        }

        

        public MenuCanceledDelegate MenuCancelled
        {
            get
            {
                return _menuCancelled;
            }

            set
            {
                _menuCancelled = value;
            }
        }
        #endregion

        #region Constructor
        public CircleMenu(int index, float radius, string menuName)
            :base(index)
        {


            _menuItemsToRender = new Queue<MenuItem>();
            Visible = false;
            _showing = false;
            _menuDepth = -1;
            _menuItems = new List<MenuItem>();
            Position = DefaultPosition;
            
            _radius = radius;

            _menuName = menuName;
            
            Size = _defaultSize;
            SimpleMaterial tempMaterial = new SimpleMaterial();
            tempMaterial.TextureFilename = @"data\images\ui\menu\menu circle.PNG";
            Material = tempMaterial;
            _menuItemsToRender.Enqueue(this);
            TorqueObjectDatabase.Instance.Register(this);
        }
        #endregion

        #region Methods
        #region Showing/Hiding
        public void Show()
        {
            if (_manager != null)
            {
                Position = _manager.MenuPosition;
            }

            foreach (MenuItem item in _menuItems)
            {
                item.Visible = true;
            }
            Visible = true;
            _showing = true;
   
            RefreshMenuPosition();
            if (_menuShown != null)
            {
                _menuShown();
            }   
        }

        public void Hide()
        {
            _showing = false;
            foreach (MenuItem item in _menuItems)
            {
                item.Visible = false;
            }
        }
        #endregion

        public void AddItem(MenuItem menuItem)
        {
            _menuItemsToRender.Enqueue(menuItem);
            _menuItems.Add(menuItem);
            if (_showing)
            {
                menuItem.Visible = true;
            }
            RefreshMenuPosition();
        }

        public void UpdateMenuItem(int index, MenuItem menuItem)
        {
            _menuItems[index].MarkForDelete = true;
            _menuItemsToRender.Enqueue(menuItem);
            _menuItems[index] = menuItem;
            if (_showing)
            {
                menuItem.Visible = true;
            }
            RefreshMenuPosition();
        }

        public void Clear()
        {
            foreach (MenuItem menuItem in _menuItems)
            {
                menuItem.MarkForDelete=true;
            }
            _menuItems.Clear();
            RefreshMenuItems();
        }

        public void RefreshMenuItems()
        {

            while (_menuItemsToRender.Count > 0)
            {
                MenuItem tempItem = _menuItemsToRender.Dequeue();
                tempItem.RefreshTexture();
                if (!tempItem.IsRegistered)
                {
                    TorqueObjectDatabase.Instance.Register(tempItem);
                }
            }
        }

        public override void RefreshTexture()
        {
            Texture2D menuItemTexture = Card.StandardBackgroundTexture;
            XyneText myText = new XyneText();
            myText.Color = Color.Black;
            myText.Position = new Vector2(10, 10);
            myText.Text = _menuName;
            myText.Font = ResourceManager.Instance.LoadFont("Arial12");

            (Material as SimpleMaterial).SetTexture(MaterialHelper.DrawTextOnTexture(menuItemTexture, myText, Size));
        }

        public void RefreshMenuPosition()
        {
            float degreeOffset = 360.0f/_menuItems.Count;
            for (int i = 0; i < _menuItems.Count; i++ )
            {
                MenuItem menuItem = _menuItems[i];
                menuItem.Position =Position - MathManager.VectorFromDegreeRadius(degreeOffset * (float)i, _radius);
            }
        }

        public void MenuCancel()
        {
            Hide();
            _manager.CancelMenu(this);
            if (_menuCancelled != null)
            {
                _menuCancelled();
            }
        }
        #region Private
        private void RefreshSelected()
        {
            if ((_selectedX != 0.0f || _selectedY != 0.0f) && (Math.Sqrt(_selectedX*_selectedX + _selectedY*_selectedY) > .5) && _menuItems.Count > 0)
            {               
                MenuItem menuItemToSelect = null;
                float currentClosestDegreeDiff = float.MinValue;

                float selectionDegree = MathManager.CalculateDegreeFromVector(new Vector2(_selectedX, _selectedY));

                foreach (MenuItem menuItemToCheck in _menuItems)
                {
                    float menuItemDegreeDiff = MathManager.DegreeCompare(selectionDegree, MathManager.CalculateDegreeFromVector(menuItemToCheck.Position - Position));

                    if (float.MinValue == currentClosestDegreeDiff || menuItemDegreeDiff < currentClosestDegreeDiff)
                    {
                        currentClosestDegreeDiff = menuItemDegreeDiff;
                        menuItemToSelect = menuItemToCheck;
                    }
                }

                    if (_currentlySelected == null)
                    {
                        menuItemToSelect.Size = menuItemToSelect.Size * 1.2f;
                        _currentlySelected = menuItemToSelect;
                        _currentlySelected.Layer = Game.SelectedMenuItemLayer;
                    }
                    else
                    {
                        if (menuItemToSelect.AutoName != _currentlySelected.AutoName)
                        {
                            if (_currentlySelected != null)
                            {
                                _currentlySelected.Size = _currentlySelected.Size * (1 / 1.2f);
                            }
                            menuItemToSelect.Size = menuItemToSelect.Size * 1.2f;
                            _currentlySelected.Layer = Game.MenuItemLayer;
                            _currentlySelected = menuItemToSelect;
                            _currentlySelected.Layer = Game.SelectedMenuItemLayer;
                        }
                    }
                
            }
            else
            {
                if (_currentlySelected != null)
                {
                    _currentlySelected.Layer = Game.MenuItemLayer;
                    _currentlySelected.Size = _currentlySelected.Size * (1 / 1.2f);
                    _currentlySelected = null;
                }
            }
        }

        public void EnableInputMap()
        {
            
            InputMap inputMap = PlayerManager.Instance.GetPlayer(0).InputMap;
            _oldInputMap = (InputMap)inputMap.Clone();
            
            int keyboardId = InputManager.Instance.FindDevice("keyboard");
            if (keyboardId >= 0)
            {
                //       inputMap.BindAction(keyboardId, (int)Keys.Escape, OnExit);

                inputMap.BindAction(keyboardId, (int)Keys.Up, OnUp);
                inputMap.BindAction(keyboardId, (int)Keys.Down, OnDown);
                inputMap.BindAction(keyboardId, (int)Keys.Left, OnLeft);
                inputMap.BindAction(keyboardId, (int)Keys.Right, OnRight);
                inputMap.BindAction(keyboardId, (int)Keys.A, OnSelect);
                inputMap.BindAction(keyboardId, (int)Keys.B, OnCancel);
            }
            int gamepadId = InputManager.Instance.FindDevice("gamepad0");
            if (gamepadId >= 0)
            {

                inputMap.BindAction(gamepadId, (int)XGamePadDevice.GamePadObjects.B, OnCancel);
                inputMap.BindAction(gamepadId, (int)XGamePadDevice.GamePadObjects.A, OnSelect);
                inputMap.BindAction(gamepadId, (int)XGamePadDevice.GamePadObjects.LeftThumbX, OnX);
                inputMap.BindAction(gamepadId, (int)XGamePadDevice.GamePadObjects.LeftThumbY, OnY);
                
            }
        }

        public void DisableInputMap()
        {
            PlayerManager.Instance.GetPlayer(0).InputMap = _oldInputMap;
        }

        public override void Selected()
        {
            _manager.Current = this;

            base.Selected();
        }
        #endregion
        #endregion

        #region Events
        #region Keyboard
        private void OnUp(float val)
        {
            _selectedY = -val;
            RefreshSelected();
        }

        private void OnDown(float val)
        {
            _selectedY = val;
            RefreshSelected();
        }

        private void OnLeft(float val)
        {
            _selectedX = -val;
            RefreshSelected();
        }

        private void OnRight(float val)
        {
            _selectedX = val;
            RefreshSelected();
        }
        #endregion

        #region Gamepad
        private void OnX(float val)
        {
            _selectedX = val;
            RefreshSelected();
        }

        private void OnY(float val)
        {
            _selectedY = -val;
            RefreshSelected();
        }
        #endregion

        #region General

        private void OnSelect(float val)
        {
            if (val > 0.0)
            {
                if (_currentlySelected != null)
                {
                    _currentlySelected.Selected();
                    if (_currentlySelected.GetType() == typeof(CircleMenu))
                    {
                        _manager.PushMenu(this);
                    }
                }
            }
        }

        private void OnCancel(float val)
        {
            if (val > 0.0 && _manager != null)
            {
                MenuCancel();
            }
        }

        
        #endregion
        #endregion
    }
}
